package com.smartcampusbackend.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.smartcampusbackend.model.User;
import com.smartcampusbackend.service.SystemLogService;
import com.smartcampusbackend.service.TokenService;
import com.smartcampusbackend.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.SimpleMailMessage;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/api/auth")
@CrossOrigin(origins = "*")
public class AuthController {
    @Autowired
    private StringRedisTemplate redisTemplate;
    private static final String CAPTCHA_PREFIX = "captcha:";
    private static final long CAPTCHA_EXPIRE_SECONDS = 5 * 60; // 5分钟
    @Autowired
    private JavaMailSender mailSender;
    @Autowired
    private UserService userService;
    @Autowired
    private SystemLogService systemLogService;
    private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    @Autowired
    private TokenService tokenService;

    @PostMapping("/register")
    public Map<String, Object> register(@RequestBody User user) {
        Map<String, Object> resp = new HashMap<>();
        try {
            if (user.getRole() == null) {
                resp.put("code", 400);
                resp.put("message", "请选择身份");
                resp.put("data", null);
                return resp;
            }
            if (user.getPassword() == null || user.getPassword().isEmpty()) {
                resp.put("code", 400);
                resp.put("message", "密码不能为空");
                resp.put("data", null);
                return resp;
            }
            String encodedPwd = new BCryptPasswordEncoder().encode(user.getPassword());
            user.setPassword(encodedPwd);
            boolean success = userService.save(user);
            if (success) {
                // 注册成功后自动生成token并返回
                String token = UUID.randomUUID().toString();
                tokenService.saveToken(token, user.getUsername());
                Map<String, Object> userInfo = new HashMap<>();
                userInfo.put("id", user.getId() != null ? user.getId().toString().trim() : null);
                userInfo.put("username", user.getUsername());
                userInfo.put("realName", user.getRealName());
                userInfo.put("role", user.getRole());
                Map<String, Object> data = new HashMap<>();
                data.put("token", token);
                data.put("userInfo", userInfo);
                resp.put("code", 200);
                resp.put("message", "注册成功");
                resp.put("data", data);
            } else {
                resp.put("code", 400);
                resp.put("message", "注册失败，用户名/学号/工号/邮箱可能已存在");
                resp.put("data", null);
            }
        } catch (Exception e) {
            resp.put("code", 500);
            resp.put("message", "注册异常：" + e.getMessage());
            resp.put("data", null);
        }
        return resp;
    }

    @PostMapping("/login")
    public Map<String, Object> login(@RequestBody Map<String, String> params, HttpServletRequest request) {
        String username = params.get("username");
        String password = params.get("password");
        String role = params.get("role");
        String captcha = params.get("captcha");
        String captchaId = params.get("captchaId");
        Map<String, Object> resp = new HashMap<>();
        String ipAddress = getClientIpAddress(request);
        String userAgent = request.getHeader("User-Agent");
        if (username == null || password == null || role == null) {
            resp.put("code", 400);
            resp.put("message", "用户名、密码和身份不能为空");
            resp.put("data", null);
            return resp;
        }
        if (captcha == null || captchaId == null) {
            resp.put("code", 400);
            resp.put("message", "验证码不能为空");
            resp.put("data", null);
            return resp;
        }
        String realCaptcha = redisTemplate.opsForValue().get(CAPTCHA_PREFIX + captchaId);
        if (realCaptcha == null || !realCaptcha.equalsIgnoreCase(captcha)) {
            resp.put("code", 400);
            resp.put("message", "验证码错误");
            resp.put("data", null);
            return resp;
        }
        redisTemplate.delete(CAPTCHA_PREFIX + captchaId);
        User user = userService.lambdaQuery()
                .eq(User::getUsername, username)
                .eq(User::getRole, role)
                .one();
        if (user == null) {
            systemLogService.logLogin(username, null, ipAddress, userAgent, "FAILED", "用户不存在或身份不匹配");
            resp.put("code", 400);
            resp.put("message", "用户不存在或身份不匹配");
            resp.put("data", null);
            return resp;
        }
        if (!new BCryptPasswordEncoder().matches(password, user.getPassword())) {
            systemLogService.logLogin(username, user.getId(), ipAddress, userAgent, "FAILED", "密码错误");
            resp.put("code", 400);
            resp.put("message", "密码错误");
            resp.put("data", null);
            return resp;
        }
        String token = UUID.randomUUID().toString();
        tokenService.saveToken(token,username);
        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("id", user.getId() != null ? user.getId().toString().trim() : null);
        userInfo.put("username", user.getUsername());
        userInfo.put("realName", user.getRealName());
        userInfo.put("role", user.getRole());
        Map<String, Object> data = new HashMap<>();
        data.put("token", token);
        data.put("userInfo", userInfo);
        resp.put("code", 200);
        resp.put("message", "登录成功");
        resp.put("data", data);
        systemLogService.logLogin(username, user.getId(), ipAddress, userAgent, "SUCCESS", "用户登录成功");
        user.setLastLogin(LocalDateTime.now());
        userService.updateById(user);
        return resp;
    }

    @GetMapping("/captcha")
    public Map<String, Object> getCaptcha(HttpServletResponse response) throws IOException {
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(120, 40, 4, 20);
        String code = lineCaptcha.getCode();
        String captchaId = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(CAPTCHA_PREFIX + captchaId, code, CAPTCHA_EXPIRE_SECONDS, TimeUnit.SECONDS);
        String base64 = lineCaptcha.getImageBase64Data();
        String img;
        if (base64.startsWith("data:image")) {
            img = base64;
        } else {
            img = "data:image/png;base64," + base64;
        }
        Map<String, Object> resp = new HashMap<>();
        resp.put("code", 200);
        resp.put("message", "success");
        Map<String, Object> data = new HashMap<>();
        data.put("img", img);
        data.put("captchaId", captchaId);
        resp.put("data", data);
        return resp;
    }

    @GetMapping("/info")
    public Map<String, Object> getUserInfo(@RequestHeader("Authorization") String token) {
        try {
            if (token == null || !token.startsWith("Bearer ")) {
                Map<String, Object> resp = new HashMap<>();
                resp.put("code", 401);
                resp.put("message", "无效的token");
                resp.put("data", null);
                return resp;
            }
            String tokenValue = token.substring(7);
            String username = tokenService.getUsernameByToken(tokenValue);
            if (username == null) {
                Map<String, Object> resp = new HashMap<>();
                resp.put("code", 401);
                resp.put("message", "token已过期或无效");
                resp.put("data", null);
                return resp;
            }
            User user = userService.lambdaQuery()
                    .eq(User::getUsername, username)
                    .one();
            if (user == null) {
                Map<String, Object> resp = new HashMap<>();
                resp.put("code", 404);
                resp.put("message", "用户不存在");
                resp.put("data", null);
                return resp;
            }
            Map<String, Object> resp = new HashMap<>();
            resp.put("code", 200);
            resp.put("message", "获取用户信息成功");
            Map<String, Object> userInfo = new HashMap<>();
            userInfo.put("id", user.getId() != null ? user.getId().toString().trim() : null);
            userInfo.put("username", user.getUsername());
            userInfo.put("name", user.getRealName());
            userInfo.put("realName", user.getRealName());
            userInfo.put("role", user.getRole());
            userInfo.put("avatar", user.getAvatar());
            userInfo.put("email", user.getEmail());
            userInfo.put("phone", user.getPhone());
            userInfo.put("registerTime", user.getCreateTime() != null ? user.getCreateTime().toString() : null);
            userInfo.put("lastLogin", user.getLastLogin() != null ? user.getLastLogin().toString() : null);
            userInfo.put("department", user.getDepartment());
            userInfo.put("major", user.getMajor());
            userInfo.put("grade", user.getGrade());
            userInfo.put("className", user.getClassName());
            userInfo.put("title", user.getTitle());
            userInfo.put("subject", user.getSubject());
            resp.put("data", userInfo);
            return resp;
        } catch (Exception e) {
            Map<String, Object> resp = new HashMap<>();
            resp.put("code", 401);
            resp.put("message", "获取用户信息失败");
            resp.put("data", null);
            return resp;
        }
    }

    @PostMapping("/logout")
    public Map<String, Object> logout(@RequestHeader("Authorization") String token) {
        try {
            if (token != null && token.startsWith("Bearer ")) {
                String tokenValue = token.substring(7);
                tokenService.removeToken(tokenValue);
            }
            Map<String, Object> resp = new HashMap<>();
            resp.put("code", 200);
            resp.put("message", "退出成功");
            resp.put("data", null);
            return resp;
        } catch (Exception e) {
            Map<String, Object> resp = new HashMap<>();
            resp.put("code", 500);
            resp.put("message", "退出失败：" + e.getMessage());
            resp.put("data", null);
            return resp;
        }
    }

    @PostMapping("/forgot-password")
    public Map<String, Object> forgotPassword(@RequestBody Map<String, String> params) {
        String email = params.get("email");
        Map<String, Object> resp = new HashMap<>();
        if (email == null) {
            resp.put("code", 400);
            resp.put("message", "邮箱不能为空");
            resp.put("data", null);
            return resp;
        }
        User user = userService.lambdaQuery().eq(User::getEmail, email).one();
        if (user == null) {
            resp.put("code", 400);
            resp.put("message", "邮箱未注册");
            resp.put("data", null);
            return resp;
        }
        String captcha = String.valueOf((int)((Math.random() * 9 + 1) * 100000));
        redisTemplate.opsForValue().set(CAPTCHA_PREFIX + email, captcha, CAPTCHA_EXPIRE_SECONDS, TimeUnit.SECONDS);
        try {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom("2928616050@qq.com");
            message.setTo(email);
            message.setSubject("智慧校园系统-找回密码验证码");
            message.setText("您的验证码是：" + captcha + "，5分钟内有效。");
            mailSender.send(message);
        } catch (Exception e) {
            resp.put("code", 500);
            resp.put("message", "邮件发送失败：" + e.getMessage());
            resp.put("data", null);
            return resp;
        }
        resp.put("code", 200);
        resp.put("message", "验证码已发送到邮箱");
        resp.put("data", null);
        return resp;
    }

    @PostMapping("/reset-password")
    public Map<String, Object> resetPassword(@RequestBody Map<String, String> params) {
        String email = params.get("email");
        String captcha = params.get("captcha");
        String newPassword = params.get("newPassword");
        Map<String, Object> resp = new HashMap<>();
        if (email == null || captcha == null || newPassword == null) {
            resp.put("code", 400);
            resp.put("message", "邮箱、验证码和新密码不能为空");
            resp.put("data", null);
            return resp;
        }
        String realCaptcha = redisTemplate.opsForValue().get(CAPTCHA_PREFIX + email);
        if (realCaptcha == null || !realCaptcha.equals(captcha)) {
            resp.put("code", 400);
            resp.put("message", "验证码错误或已过期");
            resp.put("data", null);
            return resp;
        }
        User user = userService.lambdaQuery().eq(User::getEmail, email).one();
        if (user == null) {
            resp.put("code", 400);
            resp.put("message", "邮箱未注册");
            resp.put("data", null);
            return resp;
        }
        user.setPassword(new BCryptPasswordEncoder().encode(newPassword));
        userService.updateById(user);
        redisTemplate.delete(CAPTCHA_PREFIX + email);
        resp.put("code", 200);
        resp.put("message", "密码重置成功");
        resp.put("data", null);
        return resp;
    }

    @PostMapping("/change-password")
    public Map<String, Object> changePassword(@RequestHeader("Authorization") String token, @RequestBody Map<String, String> params) {
        String oldPassword = params.get("oldPassword");
        String newPassword = params.get("newPassword");
        String email = params.get("email");
        String captcha = params.get("captcha");
        Map<String, Object> resp = new HashMap<>();
        if (token == null || !token.startsWith("Bearer ")) {
            resp.put("code", 401);
            resp.put("message", "无效的token");
            resp.put("data", null);
            return resp;
        }
        String tokenValue = token.substring(7);
        String username = tokenService.getUsernameByToken(tokenValue);
        if (username == null) {
            resp.put("code", 401);
            resp.put("message", "token已过期或无效");
            resp.put("data", null);
            return resp;
        }
        if (oldPassword == null || newPassword == null || email == null || captcha == null) {
            resp.put("code", 400);
            resp.put("message", "所有字段都不能为空");
            resp.put("data", null);
            return resp;
        }
        String realCaptcha = redisTemplate.opsForValue().get(CAPTCHA_PREFIX + email);
        if (realCaptcha == null || !realCaptcha.equals(captcha)) {
            resp.put("code", 400);
            resp.put("message", "验证码错误或已过期");
            resp.put("data", null);
            return resp;
        }
        User user = userService.lambdaQuery().eq(User::getUsername, username).one();
        if (user == null) {
            resp.put("code", 404);
            resp.put("message", "用户不存在");
            resp.put("data", null);
            return resp;
        }
        if (!new BCryptPasswordEncoder().matches(oldPassword, user.getPassword())) {
            resp.put("code", 400);
            resp.put("message", "原密码错误");
            resp.put("data", null);
            return resp;
        }
        if (oldPassword.equals(newPassword)) {
            resp.put("code", 400);
            resp.put("message", "新密码不能与原密码相同");
            resp.put("data", null);
            return resp;
        }
        user.setPassword(new BCryptPasswordEncoder().encode(newPassword));
        userService.updateById(user);
        redisTemplate.delete(CAPTCHA_PREFIX + email);
        resp.put("code", 200);
        resp.put("message", "密码修改成功");
        resp.put("data", null);
        return resp;
    }

    @PostMapping("/send-change-password-captcha")
    public Map<String, Object> sendChangePasswordCaptcha(@RequestHeader("Authorization") String token, @RequestBody Map<String, String> params) {
        String email = params.get("email");
        Map<String, Object> resp = new HashMap<>();
        if (token == null || !token.startsWith("Bearer ")) {
            resp.put("code", 401);
            resp.put("message", "无效的token");
            resp.put("data", null);
            return resp;
        }
        String tokenValue = token.substring(7);
        String username = tokenService.getUsernameByToken(tokenValue);
        if (username == null) {
            resp.put("code", 401);
            resp.put("message", "token已过期或无效");
            resp.put("data", null);
            return resp;
        }
        if (email == null) {
            resp.put("code", 400);
            resp.put("message", "邮箱不能为空");
            resp.put("data", null);
            return resp;
        }
        User user = userService.lambdaQuery().eq(User::getUsername, username).one();
        if (user == null) {
            resp.put("code", 404);
            resp.put("message", "用户不存在");
            resp.put("data", null);
            return resp;
        }
        if (!email.equals(user.getEmail())) {
            resp.put("code", 400);
            resp.put("message", "邮箱与当前用户不匹配");
            resp.put("data", null);
            return resp;
        }
        String captcha = String.valueOf((int)((Math.random() * 9 + 1) * 100000));
        redisTemplate.opsForValue().set(CAPTCHA_PREFIX + email, captcha, CAPTCHA_EXPIRE_SECONDS, TimeUnit.SECONDS);
        try {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom("2928616050@qq.com");
            message.setTo(email);
            message.setSubject("智慧校园系统-修改密码验证码");
            message.setText("您的验证码是：" + captcha + "，5分钟内有效。");
            mailSender.send(message);
        } catch (Exception e) {
            resp.put("code", 500);
            resp.put("message", "邮件发送失败：" + e.getMessage());
            resp.put("data", null);
            return resp;
        }
        resp.put("code", 200);
        resp.put("message", "验证码已发送到邮箱");
        resp.put("data", null);
        return resp;
    }

    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }
        return request.getRemoteAddr();
    }
}